package com.joysuch.wwyt.bp.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.bp.bean.risk.BpCompanyBean;
import com.joysuch.wwyt.bp.bean.risk.BpCompanyDto;
import com.joysuch.wwyt.bp.bean.risk.BpTeamSpecialBean;
import com.joysuch.wwyt.bp.entity.risk.BpCompany;
import com.joysuch.wwyt.bp.entity.risk.BpJudgeDepart;
import com.joysuch.wwyt.bp.enums.RiskJudgeStates;
import com.joysuch.wwyt.bp.repository.BpCompanyRepository;
import com.joysuch.wwyt.bp.repository.BpDepartRepository;
import com.joysuch.wwyt.bp.service.BpRiskCompanyService;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.enums.BaseConfigCodes;
import com.joysuch.wwyt.core.enums.RiskLevels;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.websocket.MonitorPointDataWebSocket;
import com.joysuch.wwyt.mh.websocket.WebsocketDataType;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author ZhangDong
 * @Date 2020/3/16 11:06
 */
@Service
@Transactional
@Slf4j
public class BpRiskCompanyServiceImpl implements BpRiskCompanyService, ApplicationRunner {

    @Autowired
    private BpCompanyRepository bpCompanyRepository;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartRepository bpDepartRepository;
    @Autowired
    private BaseConfigService baseConfigService;

    @Override
    public ResultBean save(BpCompanyBean bpCompanyBean) {
        LocalDate announceTime = bpCompanyBean.getAnnounceTime();
        Long id = bpCompanyBean.getId();
        /*//日期小于当天没有意义
        if (announceTime.isBefore(LocalDate.now())) {
            return ResultBean.fail(101, "请填写今天/未来的公告时间");
        }*/
        //新增，公告时间已有记录存在
        List<BpCompany> tempList = bpCompanyRepository.findByAnnounceTime(announceTime);
        if (!CollectionUtils.isEmpty(tempList) && id == null) {
            return ResultBean.fail(101, announceTime + " 已有记录，在相应记录下修改即可");
        }

        BpCompany bpCompany;
        if (id == null) {
            bpCompany = new BpCompany();
            if (announceTime.isBefore(LocalDate.now())) {
                bpCompany.setAnnounceStatus(RiskJudgeStates.ANNOUNCED.getState());
            } else {
                bpCompany.setAnnounceStatus(RiskJudgeStates.WAIT_ANNOUNCE.getState());
            }
            bpCompany.setReleaseUserName(baseUserDao.getBaseUserNameById(Context.getCurrentUserId()));
        } else {
            bpCompany = bpCompanyRepository.findById(id).orElseThrow(() -> new RuntimeException("新增无需传id"));
        }
        int announcingFlag = 0;
        if (id != null && RiskJudgeStates.ANNOUNCE_ING.getState().equals(bpCompany.getAnnounceStatus())) {
            if (!bpCompanyBean.getAnnounceTime().equals(bpCompany.getAnnounceTime())) {
                return ResultBean.fail(101, "正在公示，不能修改公示时间");
            }
            announcingFlag = 1;
        }
        BeanUtils.copyProperties(bpCompanyBean, bpCompany);
        bpCompany.setTenentId(Context.getCurrentTenantId());
        bpCompany.setOrgCode(Context.getCurrentOrgCode());
        bpCompany.setSpecialWork(JSON.toJSONString(bpCompanyBean.getSpecialBeanList()));
        if (announcingFlag == 1) {
            //正在公示，通知
            sendWebsocketDetail(bpCompany);
        }

        //新增，当天如果没有正在公示，并且时间已过9点57，加入，已公示，替换

        //取配置项的时间
        BaseConfig baseConfig = baseConfigService.findFirstConfig(BaseConfigCodes.DEFAULT_TIME_OF_ANNOUNCEMENT);
        Integer configHour = 9;
        Integer configMinute = 57;
        if (baseConfig!=null&& org.apache.commons.lang3.StringUtils.isNotBlank(baseConfig.getValue())) {
            configHour = Integer.parseInt(baseConfig.getValue().substring(0, 2));
            configMinute = Integer.parseInt(baseConfig.getValue().substring(0, 2));
        }
        LocalTime ten = LocalTime.of(configHour, configMinute, 0);
        int count = bpCompanyRepository.countByAnnounceStatusAndAnnounceTime(RiskJudgeStates.ANNOUNCE_ING.getState(), LocalDate.now());
        if (id == null && count == 0 && LocalDate.now().equals(bpCompanyBean.getAnnounceTime()) && LocalTime.now().isAfter(ten)) {
            bpCompany.setAnnounceStatus(RiskJudgeStates.ANNOUNCE_ING.getState());
            sendWebsocketDetail(bpCompany);
            updateBeforeToday();
        }
        bpCompanyRepository.save(bpCompany);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    public ResultBean showData(LocalDate announceTime) {
        List<BpJudgeDepart> departList = bpDepartRepository.findByReportDateAndReleaseStatus(announceTime, RiskJudgeStates.REPORTED.getState());
        if (CollectionUtils.isEmpty(departList)) {
            return ResultBean.defaultSuccessResult();
        }
        List<BpTeamSpecialBean> list = Lists.newArrayList();
        for (BpJudgeDepart r : departList) {
            String specialWork = r.getSpecialWork();
            List<BpTeamSpecialBean> specialBeanList = JSON.parseArray(specialWork, BpTeamSpecialBean.class);
            for (BpTeamSpecialBean bpTeamSpecialBean : specialBeanList) {
                list.add(bpTeamSpecialBean);
            }
        }
        List<BpTeamSpecialBean> resultList = Lists.newArrayList();
        Map<String, List<BpTeamSpecialBean>> map = new HashMap<>();
        for (BpTeamSpecialBean bpTeamSpecialBean : list) {
            if (bpTeamSpecialBean == null) {
                continue;
            }
            String specialWorkName = bpTeamSpecialBean.getSpecialWorkName();
            List<BpTeamSpecialBean> specialBeanList = map.get(specialWorkName);
            if (specialBeanList == null) {
                specialBeanList = Lists.newArrayList();
            }
            specialBeanList.add(bpTeamSpecialBean);
            map.put(specialWorkName, specialBeanList);
        }
        for (List<BpTeamSpecialBean> value : map.values()) {
            resultList.add(new BpTeamSpecialBean(value.get(0).getSpecialWorkName(), value.stream().collect(Collectors.summingInt(BpTeamSpecialBean::getSum))));
        }
        return ResultBean.success(resultList);
    }

    @Override
    public ResultBean delete(Long id) {
        BpCompany bpCompany = bpCompanyRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("操作失败"));
        if (RiskJudgeStates.ANNOUNCE_ING.getState().equals(bpCompany.getAnnounceStatus())) {
            BpCompany bpCompany1 = new BpCompany();
            bpCompany1.setTenentId(Context.getCurrentTenantId());
            bpCompany1.setOrgCode(Context.getCurrentOrgCode());
            sendWebsocketDetail(bpCompany1);
        }
        bpCompanyRepository.deleteById(id);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    public ResultBean getById(Long id) {
        BpCompany bpCompany = bpCompanyRepository.findById(id).orElse(new BpCompany());
        if (bpCompany.getId() == null) {
            return ResultBean.defaultSuccessResult();
        }
        BpCompanyDto bpCompanyDto = new BpCompanyDto();
        BeanUtils.copyProperties(bpCompany, bpCompanyDto);
        bpCompanyDto.setRiskLevelName(RiskLevels.findRiskLevelName(bpCompany.getRiskLevel()));
        bpCompanyDto.setSpecialBeanList(JSON.parseArray(bpCompany.getSpecialWork(), BpTeamSpecialBean.class));
        return ResultBean.success(bpCompanyDto);
    }

    @Override
    public ResultBean page(Pageable pageable, LocalDate announceTime) {
        pageable = PageDataUtils.addOrderByDesc(pageable, "id");
        Specification<BpCompany> querySpecifi = new Specification<BpCompany>() {
            @Override
            public Predicate toPredicate(Root<BpCompany> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (announceTime != null) {
                    predicates.add(cb.equal(root.get("announceTime"), announceTime));
                }
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        Page<BpCompany> all = bpCompanyRepository.findAll(querySpecifi, pageable);
        List<Long> userIdList = all.getContent().stream().map(r -> r.getUpdateBy()).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Long, String> userMap = baseUserDao.findAllById(userIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getRealName()));
        //发布人跟新人
        for (BpCompany bpCompany : all) {
            String name = userMap.get(bpCompany.getUpdateBy());
            bpCompany.setReleaseUserName(StringUtils.isEmpty(name) ? bpCompany.getReleaseUserName() : name);
        }
        return ResultBean.pageData(all.getContent(), all.getTotalElements());
    }

    @Override
    public Map<String, BpCompany> getAnnounceMsg() {
//        return WebSocket.getScreenMap();
        return MonitorPointDataWebSocket.getScreenMap();
    }

    @Override
     public void updateState(){
        getAnnouce();
    }


    /**
     * 每天上午10点更新公告
     */
//    @Scheduled(cron = "${risk.judge.company.schedule}")
    public void updateAnnounce() {

        getAnnouce();
    }

    @Override
    public void run(ApplicationArguments args) {
        processRestart();
    }

    private void getAnnouce() {
        //将过期的改状态
        updateBeforeToday();
        //取当天，如果有多条，取最新的一条
        List<BpCompany> list = bpCompanyRepository.findByAnnounceTime(LocalDate.now());
        if (CollectionUtils.isEmpty(list)) {
            //清除所有
            resetWebsocketContent(Lists.newArrayList());
            return;
        }

        //针对不同orgCode做分组
        Map<String, List<BpCompany>> map = list.stream().map(r -> {
            BpCompany bpCompany = new BpCompany();
            BeanUtils.copyProperties(r, bpCompany);
            bpCompany.setOrgCode(bpCompany.getOrgCode().substring(0, 7));
            return bpCompany;
        }).collect(Collectors.groupingBy(BpCompany::getOrgCode));
        List<Long> needUpdate = Lists.newArrayList();
        List<BpCompany> needAnnounce = Lists.newArrayList();
        for (List<BpCompany> value : map.values()) {
            List<BpCompany> bpCompanies = value.stream().sorted(Comparator.comparing(BpCompany::getCreateTime).reversed()).collect(Collectors.toList());
            BpCompany bpCompany = bpCompanies.get(0);
            needUpdate.add(bpCompany.getId());
            needAnnounce.add(bpCompany);
            sendWebsocketDetail(bpCompany);
        }
        //清除没公告的
        resetWebsocketContent(needAnnounce);

        List<BpCompany> collect1 = needUpdate.stream().map(r -> {
            BpCompany bpCompany = bpCompanyRepository.findById(r).get();
            bpCompany.setAnnounceStatus(RiskJudgeStates.ANNOUNCE_ING.getState());
            return bpCompany;
        }).collect(Collectors.toList());
        bpCompanyRepository.saveAll(collect1);
    }

    /**
     * 今天之前的数据改状态
     */
    private void updateBeforeToday() {
        List<BpCompany> bpCompanyList = bpCompanyRepository.findByAnnounceStatusNotAndAnnounceTimeLessThan(
                RiskJudgeStates.ANNOUNCED.getState(), LocalDate.now());
        for (BpCompany company : bpCompanyList) {
            if (RiskJudgeStates.WAIT_ANNOUNCE.getState().equals(company.getAnnounceStatus())) {
                company.setAnnounceStatus(RiskJudgeStates.EXPIRE_NOT_RELEASE.getState());
            } else if (RiskJudgeStates.ANNOUNCE_ING.getState().equals(company.getAnnounceStatus())) {
                company.setAnnounceStatus(RiskJudgeStates.ANNOUNCED.getState());
            }
        }
        bpCompanyRepository.saveAll(bpCompanyList);
    }

    public void processRestart() {
        List<BpCompany> list = bpCompanyRepository.findByAnnounceStatus(RiskJudgeStates.ANNOUNCE_ING.getState());
        if (!CollectionUtils.isEmpty(list)) {
            for (BpCompany bpCompany : list) {
                sendWebsocketDetail(bpCompany);
            }
            return;
        }
        getAnnouce();
    }

    private void sendWebsocketDetail(BpCompany bpCompany) {
//        WebSocket.putBigScreenMap(bpCompany);
//        WebSocket.sendInfo(bpCompany);

        MonitorPointDataWebSocket.putBigScreenMap(bpCompany);
        MonitorPointDataWebSocket.sendInfo(Lists.newArrayList(bpCompany), WebsocketDataType.RISK_COMPANY.getIndex());
    }

    private void resetWebsocketContent(List<BpCompany> list) {
        //WebSocket.resetWebsocketContent(list);

        MonitorPointDataWebSocket.resetWebsocketContent(list);
    }
}
